import os
import json
import threading
from time import sleep
from tkinter import Tk, filedialog, messagebox, simpledialog, Toplevel, Listbox, Button, Label, Entry
import shutil
from cryptography.fernet import Fernet # type: ignore

# 数据存储路径
tasks_file = "tasks.json"
logs_file = "sync_logs.json"
default_file_display_count = 5

# 全局字典管理任务线程
task_threads = {}
task_exit_flags = {}  # 用于管理任务的退出标志位
task_pause_flags = {}  # 用于管理任务的暂停标志位

def load_tasks():
    if not os.path.exists(tasks_file):
        return []
    with open(tasks_file, "r") as f:
        return json.load(f)

def save_tasks(tasks):
    with open(tasks_file, "w") as f:
        json.dump(tasks, f, indent=4)

def log_sync_event(event):
    logs = []
    if os.path.exists(logs_file):
        with open(logs_file, "r") as f:
            logs = json.load(f)
    logs.append(event)
    with open(logs_file, "w") as f:
        json.dump(logs, f, indent=4)

# 主界面
def main_menu():
    root = Tk()
    root.title("文件同步工具")

    def open_create_task():
        create_task(root)

    def open_manage_tasks():
        manage_tasks(root)

    def open_view_logs():
        view_logs(root)

    def open_set_file_display_count():
        set_file_display_count(root)

    Button(root, text="新建任务", command=open_create_task, width=20).pack(pady=5)
    Button(root, text="管理任务", command=open_manage_tasks, width=20).pack(pady=5)
    Button(root, text="查看同步日志", command=open_view_logs, width=20).pack(pady=5)
    Button(root, text="设置文件显示个数", command=open_set_file_display_count, width=20).pack(pady=5)
    Button(root, text="退出", command=root.quit, width=20).pack(pady=5)

    root.mainloop()

# 新建任务功能
def create_task(root):
    def save_task():
        source_folder = filedialog.askdirectory(title="选择源文件夹")
        if not source_folder:
            messagebox.showerror("错误", "未选择源文件夹！")
            return

        target_folder = filedialog.askdirectory(title="选择目标文件夹")
        if not target_folder:
            messagebox.showerror("错误", "未选择目标文件夹！")
            return

        task_name = simpledialog.askstring("任务命名", "请输入任务名称:")
        if not task_name:
            messagebox.showerror("错误", "任务名称不能为空！")
            return

        tasks = load_tasks()
        tasks.append({
            "name": task_name,
            "source": source_folder,
            "target": target_folder,
            "encryption": None,
            "key": None
        })
        save_tasks(tasks)
        messagebox.showinfo("成功", f"任务 \"{task_name}\" 已保存！")

    save_task()

# 管理任务功能
def manage_tasks(root):
    tasks = load_tasks()
    if not tasks:
        messagebox.showinfo("信息", "当前没有任务可供管理！")
        return

    manage_window = Toplevel(root)
    manage_window.title("管理任务")

    Label(manage_window, text="任务列表:").pack(pady=5)

    task_listbox = Listbox(manage_window, width=50, height=15)
    task_listbox.pack(pady=5)

    for task in tasks:
        task_listbox.insert("end", f"{task['name']} (源: {task['source']}, 目标: {task['target']})")

    def perform_action(action):
        selected_index = task_listbox.curselection()
        if not selected_index:
            messagebox.showerror("错误", "请选择一个任务！")
            return

        task = tasks[selected_index[0]]
        if action == "sync":
            sync_task(task)
        elif action == "pause":
            pause_sync(task)
        elif action == "delete":
            delete_task(tasks, task)
            task_listbox.delete(selected_index)
        elif action == "encrypt":
            encrypt_task(tasks, task)
        elif action == "decrypt":
            decrypt_task(tasks, task)

    Button(manage_window, text="同步", command=lambda: perform_action("sync"), width=15).pack(side="left", padx=5, pady=5)
    Button(manage_window, text="暂停同步", command=lambda: perform_action("pause"), width=15).pack(side="left", padx=5, pady=5)
    Button(manage_window, text="删除", command=lambda: perform_action("delete"), width=15).pack(side="left", padx=5, pady=5)
    Button(manage_window, text="加密", command=lambda: perform_action("encrypt"), width=15).pack(side="left", padx=5, pady=5)
    Button(manage_window, text="解密", command=lambda: perform_action("decrypt"), width=15).pack(side="left", padx=5, pady=5)

# 查看同步日志功能
def view_logs(root):
    logs = []
    if os.path.exists(logs_file):
        with open(logs_file, "r") as f:
            logs = json.load(f)

    log_window = Toplevel(root)
    log_window.title("同步日志")

    Label(log_window, text="同步日志:").pack(pady=5)
    log_listbox = Listbox(log_window, width=50, height=15)
    log_listbox.pack(pady=5)

    for log in logs:
        log_listbox.insert("end", str(log))

# 设置文件显示个数功能
def set_file_display_count(root):
    def save_count():
        try:
            count = int(entry.get())
            global default_file_display_count
            default_file_display_count = count
            messagebox.showinfo("成功", "文件显示个数已更新！")
            setting_window.destroy()
        except ValueError:
            messagebox.showerror("错误", "请输入有效的数字！")

    setting_window = Toplevel(root)
    setting_window.title("设置文件显示个数")

    Label(setting_window, text="请输入文件显示个数:").pack(pady=5)
    entry = Entry(setting_window)
    entry.pack(pady=5)
    Button(setting_window, text="保存", command=save_count).pack(pady=5)

# 同步任务功能
def sync_task(task):
    global task_threads, task_exit_flags, task_pause_flags
    if task['name'] in task_threads:
        messagebox.showerror("错误", f"任务 \"{task['name']}\" 已在同步中！")
        return

    interval = simpledialog.askinteger("同步间隔", "请输入同步时间间隔（秒）:")
    if interval is None or interval <= 0:
        messagebox.showerror("错误", "时间间隔必须是正整数！")
        return

    task_exit_flags[task['name']] = False  # 初始化退出标志位
    task_pause_flags[task['name']] = False  # 初始化暂停标志位
    thread = threading.Thread(target=sync_process, args=(task['name'], task['source'], task['target'], interval, task), daemon=True)
    task_threads[task['name']] = thread
    thread.start()

def sync_process(task_name, source, target, interval, task):
    try:
        cipher_suite = None
        if task['key']:
            cipher_suite = Fernet(task['key'].encode('utf-8'))

        print(f"开始同步任务 \"{task_name}\"，时间间隔为 {interval} 秒...")
        while not task_exit_flags.get(task_name, False):  # 检查退出标志
            if task_pause_flags.get(task_name, False):  # 检查暂停标志
                sleep(1)  # 如果暂停，则等待一秒再检查
                continue

            for root, _, files in os.walk(source):
                for file in files:
                    src_path = os.path.join(root, file)
                    rel_path = os.path.relpath(src_path, source)
                    dest_path = os.path.join(target, rel_path)
                    os.makedirs(os.path.dirname(dest_path), exist_ok=True)

                    if cipher_suite and task['encryption'] == "source":
                        with open(src_path, 'rb') as src_file:
                            encrypted_data = cipher_suite.encrypt(src_file.read())
                        with open(dest_path, 'wb') as dest_file:
                            dest_file.write(encrypted_data)
                    elif cipher_suite and task['encryption'] == "target":
                        with open(src_path, 'rb') as src_file:
                            data = src_file.read()
                        with open(dest_path, 'wb') as dest_file:
                            dest_file.write(cipher_suite.encrypt(data))
                    else:
                        shutil.copy2(src_path, dest_path)

                    print(f"同步文件: {file}")
            log_sync_event({"task": task_name, "status": "success"})
            sleep(interval)
    except Exception as e:
        print(f"同步任务失败: {e}")
    finally:
        print(f"任务 \"{task_name}\" 同步线程已停止。")
        task_threads.pop(task_name, None)
        task_exit_flags.pop(task_name, None)
        task_pause_flags.pop(task_name, None)

# 暂停同步功能
def pause_sync(task):
    global task_pause_flags
    if task['name'] not in task_threads:
        messagebox.showerror("错误", f"任务 \"{task['name']}\" 未在同步中！")
        return

    if not task_pause_flags.get(task['name'], False):
        task_pause_flags[task['name']] = True
        messagebox.showinfo("成功", f"任务 \"{task['name']}\" 已暂停同步！")
    else:
        task_pause_flags[task['name']] = False
        messagebox.showinfo("成功", f"任务 \"{task['name']}\" 已恢复同步！")

# 删除任务功能
def delete_task(tasks, task):
    global task_threads, task_exit_flags, task_pause_flags
    if task['name'] in task_threads:
        print(f"正在停止任务 \"{task['name']}\" 的同步进程...")
        task_exit_flags[task['name']] = True  # 设置退出标志
        task_threads[task['name']].join()    # 等待线程退出
        print(f"任务 \"{task['name']}\" 的同步进程已停止。")

    task_pause_flags.pop(task['name'], None)  # 移除暂停标志
    tasks.remove(task)
    save_tasks(tasks)
    messagebox.showinfo("成功", f"任务 \"{task['name']}\" 已删除！")

# 加密功能
def encrypt_task(tasks, task):
    if task['name'] in task_threads:
        if messagebox.askyesno("同步运行中", f"任务 \"{task['name']}\" 正在同步，是否暂停同步后设置加密？"):
            pause_sync(task)
        else:
            return

    def select_encryption():
        choice = simpledialog.askstring("加密选项", "选择加密方式: source, target, both")
        if choice not in ["source", "target", "both"]:
            messagebox.showerror("错误", "无效的选择！")
            return

        key = Fernet.generate_key()
        task['key'] = key.decode('utf-8')
        task['encryption'] = choice
        save_tasks(tasks)

        messagebox.showinfo("成功", f"任务 \"{task['name']}\" 已设置加密！秘钥: {task['key']}")

    select_encryption()

# 解密功能
def decrypt_task(tasks, task):
    if not task['encryption']:
        messagebox.showinfo("信息", "任务未加密，无需解密！")
        return

    key = task['key']
    cipher_suite = Fernet(key.encode('utf-8'))

    def decrypt_file(filepath):
        try:
            with open(filepath, 'rb') as file:
                encrypted_data = file.read()
            decrypted_data = cipher_suite.decrypt(encrypted_data)
            with open(filepath, 'wb') as file:
                file.write(decrypted_data)
        except cryptography.fernet.InvalidToken:
            print(f"跳过未加密或损坏的文件: {filepath}")

    for root, _, files in os.walk(task['source']):
        for file in files:
            decrypt_file(os.path.join(root, file))

    task['encryption'] = None
    task['key'] = None
    save_tasks(tasks)
    messagebox.showinfo("成功", f"任务 \"{task['name']}\" 已解密！")

if __name__ == "__main__":
    main_menu()